﻿using AutoMapper;
using Microsoft.EntityFrameworkCore;
using QMERP.Domain.Dtos;
using QMERP.Domain.Entities;
using QMERP.Infrastructure.CustomException;
using QMERP.Infrastructure.EFCore;
using QMERP.Infrastructure.EFCore.Extensions;
using QMERP.Infrastructure.Extensions;
using System.Data;

namespace QMERP.Application.Services
{
    public class LensService : ILensService
    {
        private readonly IMapper _mapper;
        private readonly QMERPDbContext _db;
        public LensService(IMapper mapper, QMERPDbContext db)
        {
            _mapper = mapper;
            _db = db;
        }
        /// <summary>
        /// 获取镜种列表基础数据
        /// </summary>
        /// <returns></returns>
        public async Task<List<LensResponse>> GetBasicLenses()
        {
            var list = await _db.Lens.ToListAsync();
            return _mapper.Map<List<LensResponse>>(list);
        }
        /// <summary>
        /// 获取此仓库可添加到库存的所有的镜种
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<List<LensResponse>> GetCanAddStockLenses(CanAddStockLensRequest request)
        {
            List<long> lensIds = _db.Stock.Where(x => x.WarehouseId == request.WarehouseId).Select(s => s.LensId).Distinct().ToList();
            var query = _db.Lens.Where(x => !lensIds.Contains(x.Id));
            if (request.SalesLensCode != null)
                query = query.Where(x => x.SalesLensCode.ToLower().Contains(request.SalesLensCode.ToLower()));
            var list = await query.ToListAsync();
            return _mapper.Map<List<LensResponse>>(list);
        }
        /// <summary>
        /// 获取此仓库库存的所有的镜种
        /// </summary>
        /// <param name="warehouseId"></param>
        /// <returns></returns>
        public async Task<List<LensResponse>> GetStockLenses(long warehouseId)
        {
            List<long> lensIds = _db.Stock.Where(x => x.WarehouseId == warehouseId).Select(s => s.LensId).Distinct().ToList();
            var list = await _db.Lens.Where(x => lensIds.Contains(x.Id)).ToListAsync();
            return _mapper.Map<List<LensResponse>>(list);
        }
        /// <summary>
        /// 获取此供应商和仓库库存的所有的镜种
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<List<LensResponse>> GetStockLenses(GetStockLensesRequest request)
        {
            var lenses = await (from a in _db.Lens
                                join b in _db.Lens_Supplier on a.Id equals b.LensId
                                join c in _db.Stock on a.Id equals c.LensId
                                where b.SupplierId == request.SupplierId && c.WarehouseId == request.WarehouseId
                                select a
             ).ToListAsync();
            return _mapper.Map<List<LensResponse>>(lenses);
        }
        /// <summary>
        /// 销售镜种窗体
        /// </summary>
        /// <returns></returns>
        public async Task<PageResponse<LensResponse>> Query(PageRequest<LensRequest> request)
        {
            var response = new PageResponse<LensResponse>();

            var query = Where(request);

            var list = await query.Paging(request.PageIndex, request.PageSize).ToListAsync();

            var suppliers = await (from a in _db.Supplier
                                   from b in a.Lens_Suppliers!
                                   where list.Select(s => s.Id).ToList().Contains(b.LensId)
                                   select a).Distinct().ToListAsync();

            var lensResponses = _mapper.Map<List<LensResponse>>(list);
            foreach (var l in lensResponses)
            {
                l.SupplierNames = suppliers.Where(x => l.SupplierIds!.Contains(x.Id)).Select(s => s.Name).ToList();
            }
            response.TotalCount = await query.CountAsync();
            response.PageIndex = request.PageIndex;
            response.PageSize = request.PageSize;
            response.List = lensResponses;
            return response;
        }
        /// <summary>
        /// 获取id的销售镜种详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<LensResponse> Detail(long id)
        {
            var model = await _db.Lens.GetAll().Include(x => x.Currency).Include(x => x.Lens_Suppliers).FindByIdAsync(id);
            var response = _mapper.Map<LensResponse>(model);
            response.SupplierNames = _db.Role.Where(x => response.SupplierIds!.Contains(x.Id)).Select(s => s.Name).ToList();
            return _mapper.Map<LensResponse>(model);
        }
        /// <summary>
        /// 销售镜种保存
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public async Task Save(LensSaveRequest request)
        {
            if (request.MinCYL > 0 || request.MaxCYL > 0)
                throw new ApiException("CYL不能大于0!");

            string degreesType = request.SalesLensCode.Substring(request.SalesLensCode.Length - 1);
            var query = _db.Lens.Where(x => x.Id != request.Id);
            if (degreesType == "+")
            {
                if (request.MinSPH < 25 || request.MaxSPH < 25)
                    throw new ApiException("+镜种SPH不能小于25!");
                query = query.Where(x => x.SalesLensCode.ToLower() == request.SalesLensCode.ToLower().TrimEnd('+') || x.SalesLensCode.ToLower() == request.SalesLensCode.ToLower());
            }
            else if (degreesType == "-")
            {
                if (request.MinSPH > 0 || request.MaxSPH > 0)
                    throw new ApiException("-镜种SPH不能大于0!");
                query = query.Where(x => x.SalesLensCode.ToLower() == request.SalesLensCode.ToLower().TrimEnd('-') || x.SalesLensCode.ToLower() == request.SalesLensCode.ToLower());
            }
            else
            {
                query = query.Where(x => x.SalesLensCode.ToLower() == request.SalesLensCode.ToLower() + "+" || x.SalesLensCode.ToLower() == request.SalesLensCode.ToLower() + "-" || x.SalesLensCode.ToLower() == request.SalesLensCode.ToLower());
            }
            if (await query.AnyAsync())
                throw new ApiException("销售镜种代码已存在!");
            if (await _db.Lens.AnyAsync(x => x.FactoryLensCode.ToLower() == request.FactoryLensCode.ToLower() && x.Id != request.Id))
                throw new ApiException("工厂镜种代码已存在!");
            //if (await _db.Lens.AnyAsync(x => x.SalesLensName.ToLower() == request.SalesLensName.ToLower() && x.Id != request.Id))
            //    throw new ApiException("销售镜种名称已存在!");
            //if (await _db.Lens.AnyAsync(x => x.FactoryLensName.ToLower() == request.FactoryLensName.ToLower() && x.Id != request.Id))
            //    throw new ApiException("工厂镜种名称已存在!");

            Lens? model = _mapper.Map<Lens>(request);
            if (request.Id != null)
            {
                model = await _db.Lens.GetAll().Include(x => x.Lens_Suppliers).FindByIdAsync(request.Id.Value);
                if (model == null)
                    throw new ApiException("镜种不存在!");

                List<Stock> stocks = await _db.Stock.Include(x => x.StockDetails).Where(x => x.LensId == model.Id).ToListAsync();
                if (stocks.Count > 0)
                {
                    if (request.MinSPH > model.MinSPH)
                        throw new ApiException("修改的MinSPH不能大于原本的值!");

                    if (request.MaxSPH < model.MaxSPH)
                        throw new ApiException("修改的MaxSPH不能小于原本的值!");

                    if (request.MinCYL > model.MinCYL)
                        throw new ApiException("修改的MinCYL不能大于原本的值!");

                    if (request.MaxCYL < model.MaxCYL)
                        throw new ApiException("修改的MaxCYL不能小于原本的值!");

                    if (request.MinSPH < model.MinSPH || request.MaxSPH > model.MaxSPH)
                    {
                        foreach (Stock stock in stocks)
                        {
                            AddStockDetails(stock.StockDetails!, request.MinSPH, model.MinSPH, model.MinCYL, model.MaxCYL);
                            AddStockDetails(stock.StockDetails!, model.MaxSPH, request.MaxSPH, model.MinCYL, model.MaxCYL);
                        }
                    }
                    if (request.MinCYL < model.MinCYL || request.MaxCYL > model.MaxCYL)
                    {
                        foreach (Stock stock in stocks)
                        {
                            AddStockDetails(stock.StockDetails!, request.MinSPH, request.MaxSPH, request.MinCYL, model.MinCYL);
                            AddStockDetails(stock.StockDetails!, request.MinSPH, request.MaxSPH, model.MaxCYL, request.MaxCYL);
                        }
                    }
                }
                model.SalesLensCode = request.SalesLensCode;
                model.FactoryLensCode = request.FactoryLensCode;
                model.SalesLensName = request.SalesLensName;
                model.FactoryLensName = request.FactoryLensName;
                model.Brand = request.Brand;
                model.LensType = request.LensType;
                model.MaxSPH = request.MaxSPH;
                model.MinSPH = request.MinSPH;
                model.MaxCYL = request.MaxCYL;
                model.MinCYL = request.MinCYL;
                model.MaxADD = request.MaxADD;
                model.MinADD = request.MinADD;
                model.Size = request.Size;
                model.CGPrice = request.CGPrice;
                model.Price = request.Price;
                //model.IsBulk = request.IsBulk;
                model.Type = request.Type;
                model.Refraction = request.Refraction;
                model.Transition = request.Transition;
                model.Vouchers = request.Vouchers;
                model.Color = request.Color;
                model.Corridor = request.Corridor;
                model.Mirror = request.Mirror;
                model.Tinting = request.Tinting;
                model.Coating = request.Coating;
                model.Cost = request.Cost;
                model.CurrencyId = request.CurrencyId;
                model.TechnologyCode = request.TechnologyCode;
                model.FocusCode = request.FocusCode;
                model.ApplyCode = request.ApplyCode;
                model.TextureCode = request.TextureCode;
                model.Unit = request.Unit;
                model.IsEnable = request.IsEnable;
                //var supplierLens = await _db.Supplier_Lens.Where(x => x.LensId == model.Id).ToListAsync();
                _db.RemoveRange(model.Lens_Suppliers);
            }
            if (request.SupplierIds != null)
            {
                List<Lens_Supplier> supplierLens = new();
                foreach (int supplierId in request.SupplierIds)
                {
                    Lens_Supplier lens_Supplier = new()
                    {
                        SupplierId = supplierId,
                        LensId = model.Id
                    };
                    supplierLens.Add(lens_Supplier);
                }
                model.Lens_Suppliers = supplierLens;
            }
            if (request.Id == null)
                await _db.Lens.AddAsync(model);
            await _db.SaveChangesAsync();
        }
        /// <summary>
        /// 销售镜种删除(真删除)
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public async Task Remove(LensRemoveRequest request)
        {
            if (request.Ids == null)
                throw new ApiException("id不能为空!");

            var lensCodes = await _db.Stock.Include(x => x.Lens).Where(x => request.Ids.Contains(x.LensId)).Select(s => s.Lens!.SalesLensCode).Distinct().ToListAsync();
            if (lensCodes.Count > 0)
            {
                string strs = "";
                lensCodes.ForEach(x => strs += x + ",");
                throw new ApiException($"销售镜种{strs.TrimEnd(',')}已在库存中,不允许删除!");
            }
            var list = await _db.Lens.GetAll().Where(x => request.Ids.Contains(x.Id)).ToListAsync();
            _db.RemoveRange(list);
            await _db.SaveChangesAsync();
        }

        private void AddStockDetails(ICollection<StockDetail> stockDetails,int minSPH,int maxSPH,int minCYL,int maxCYL)
        {
            for (int sph = minSPH; sph <= maxSPH; sph += 25)
            {
                string degreesType = "-/";
                if (sph > 0)
                    degreesType = "+/";
                else
                    degreesType += "-";

                for (int cyl = minCYL; cyl <= maxCYL; cyl += 25)
                {
                    if (stockDetails.Any(x => x.SPH == sph && x.CYL == cyl))
                        continue;
                    StockDetail detail = new()
                    {
                        DegreesType = degreesType,
                        SPH = sph,
                        CYL = Math.Abs(cyl),
                        Qty = 0,
                        BasicQty = 0
                    };
                    stockDetails.Add(detail);
                }
            }
        }

        private IQueryable<Lens> Where(PageRequest<LensRequest> request)
        {
            IQueryable<Lens> query = _db.Lens.Include(x => x.Currency).Include(x => x.Lens_Suppliers).GetAll();
            if (!request.Query.SalesLensCode.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.SalesLensCode.Contains(request.Query.SalesLensCode!));
            }
            if (!request.Query.FactoryLensCode.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.FactoryLensCode.Contains(request.Query.FactoryLensCode!));
            }
            if (!request.Query.Brand.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.Brand.Contains(request.Query.Brand!));
            }
            if (request.Query.SupplierId != null)
            {
                query = query.GetBySupplierIds(request.Query.SupplierId.Value);
            }
            return query.OrderByDescending(x => x.CreatedOn);
        }
    }
}
